/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package niseeDatabase;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Struct;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import javax.persistence.Persistence;
import javax.persistence.Query;
import niseeEntity.NiseeAnswer;
import niseeEntity.NiseeColour;
import niseeEntity.NiseeColourCombo;
import niseeEntity.NiseeColourComboSet;
import niseeEntity.NiseeFormatGapsize;
import niseeEntity.NiseeImage;
import niseeEntity.NiseePercentageSize;
import niseeEntity.NiseeShape;
import niseeEntity.NiseeShapeCoor;
import niseeEntity.NiseeTestGroup;
import niseeEntity.NiseeTestShape;
import niseeEntity.NiseeTestSingle;
import niseeEntity.NiseeTestType;
import niseeEntity.NiseeUser;

import niseeImageGenerator.ImageGenerator;
import niseeImageGenerator.niCircle;
import niseeImageGenerator.niShape;
import niseeImageGenerator.niSquare;
import niseeUtility.ColourCombo;
import niseeUtility.TestType;

/**
 *
 * @author Crespo
 */
public class niseeDB {

    private String PERSISTENCE_UNIT_NAME = "NiSeeFinalPU";
    private EntityManagerFactory emf;
    private EntityManager em;
    private static int DEFAULTCOLOUR = 42;
    private static String MAXID = "SELECT MAX(n.imageIMAGEID) FROM NiseeImage n";
    private static String IDs = "SELECT n.imageIMAGEID FROM NiseeImage n";
    private static String MAXGROUP = "SELECT MAX(n.testGROUP) FROM NiseeTestGroup n WHERE n.userUSERNAME = :userUSERNAME";
    private static String CLEANGROUP = "DELETE  FROM NiseeTestGroup n WHERE n.testGroupId = :testGroupId";
    private static String TESTTYPES = "SELECT n.name FROM NiseeTestType n";
    private static String TYPE_ID_BY_NAME = "SELECT n.colour_comboset_id FROM NiseeTestType n WHERE n.name = :name";

    //private static String COLOURCOMBOSETS = "SELECT DISTINCT n.name FROM NiseeColourComboSet n";
    public niseeDB() {
        emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
        em = emf.createEntityManager();
    }

    /*public List<String> getTestTypes() {
    Query q = em.createQuery(TESTTYPES);
    List<String> sets = q.getResultList();
    return sets;
    }*/
    public List<NiseeTestType> getNiseeTestTypes() {
        Query q = em.createNamedQuery("NiseeTestType.findAll");
        List<NiseeTestType> resultList = q.getResultList();
        return resultList;

    }

    public void setTestTypesColourSet(int testTypeID, int coloursetID){
        NiseeTestType testType = getTestTypeByID2(testTypeID);
        testType.setColourCombosetId(coloursetID);
        em.getTransaction().begin();
        em.persist(testType);
        em.getTransaction().commit();
    }

    public class Usage {

        String username;
        int usage;

        public Usage(String username, int usage) {
            this.username = username;
            this.usage = usage;
        }

        public String getUsername() {
            return username;
        }

        ;

        public int getUsage() {
            return usage;
        }

        ;
    }

    public int getUsage(NiseeUser user) {
        int totalUsage = 0;
        Collection<NiseeTestGroup> testGroups = user.getNiseeTestGroupCollection();
        for (NiseeTestGroup testGroup : testGroups) {
            totalUsage += testGroup.getNiseeTestSingleCollection().size();
            /*Collection<NiseeTestSingle> testSingles =  testGroup.getNiseeTestSingleCollection();
            for(NiseeTestSingle testSingle: testSingles){
            testSingle.getImages();
            }*/
        }
        return totalUsage;
    }

    public List<Usage> getImageUsageStats(int max) {
        List<Usage> usages = new ArrayList<Usage>();
        List<NiseeUser> users = getUsers();
        for (NiseeUser user : users) {
            Usage u = new Usage(user.getUserUSERNAME(), getUsage(user));
            if (u.usage > 0) {
                usages.add(u);
            }
        }
        Collections.sort(usages, new Comparator<Usage>() {

            public int compare(Usage o1, Usage o2) {
                if (o1.usage == o2.usage) {
                    return 0;
                }
                if (o1.usage > o2.usage) {
                    return -1;
                } else {
                    return 1;
                }
            }
        });

        int numberOfActiveUsers = usages.size();
        if (numberOfActiveUsers <= max) {
            return usages.subList(0, numberOfActiveUsers);
        }

        List<Usage> topUsages = usages.subList(0, max - 1);
        List<Usage> otherUsages = usages.subList(max, usages.size());
        int otherUsagesUsage = 0;
        for (Usage otherUsage : otherUsages) {
            otherUsagesUsage += otherUsage.usage;
        }
        topUsages.add(new Usage("Other", otherUsagesUsage));
        return topUsages;
    }

    public int getFailStat(NiseeUser user) {
        int totalFails = 0;
        Collection<NiseeTestGroup> testGroups = user.getNiseeTestGroupCollection();
        for (NiseeTestGroup testGroup : testGroups) {
            System.out.println("diagnose: " + testGroup.getTestDIAGNOSIS());
            if (testGroup.getTestDIAGNOSIS().equalsIgnoreCase("FAIL")) {
                totalFails++;
            }
        }
        return totalFails;
    }

    public List<Usage> getTestFailStats(int max) {
        List<Usage> failStats = new ArrayList<Usage>();
        List<NiseeUser> users = getUsers();
        for (NiseeUser user : users) {
            Usage u = new Usage(user.getUserUSERNAME(), getFailStat(user));
            if (u.usage > 0) {
                System.out.println("FAIL");
                failStats.add(u);
            }
        }
        Collections.sort(failStats, new Comparator<Usage>() {

            public int compare(Usage o1, Usage o2) {
                if (o1.usage == o2.usage) {
                    return 0;
                }
                if (o1.usage > o2.usage) {
                    return -1;
                } else {
                    return 1;
                }
            }
        });

        int numberOfActiveUsers = failStats.size();
        if (numberOfActiveUsers <= max) {
            System.out.println("numberOfActiveUsers:" + numberOfActiveUsers);
            return failStats.subList(0, numberOfActiveUsers);
        }
        System.out.println("numberOfActiveUsers2:" + numberOfActiveUsers);
        List<Usage> topUsages = failStats.subList(0, max - 1);
        List<Usage> otherUsages = failStats.subList(max, failStats.size());
        int otherUsagesUsage = 0;
        for (Usage otherUsage : otherUsages) {
            otherUsagesUsage += otherUsage.usage;
        }
        topUsages.add(new Usage("Other", otherUsagesUsage));
        return topUsages;
    }

    public NiseeTestType getTestTypeByID2(int id) {
        Query q = em.createNamedQuery("NiseeTestType.findByTypeId");
        q.setParameter("typeId", id);
        return  (NiseeTestType) q.getSingleResult();
    }
    public TestType getTestTypeByID(int id) {
        Query q = em.createNamedQuery("NiseeTestType.findByTypeId");
        q.setParameter("typeId", id);
        NiseeTestType niseeTestType = (NiseeTestType) q.getSingleResult();
        TestType testType = new TestType((int) niseeTestType.getTypeId(),
                niseeTestType.getColourCombosetId(),
                niseeTestType.getName());
        return testType;
    }

    public List<String> getComboDistinctSetNames() {
        Query q = em.createNamedQuery("NiseeColourComboSet.findAllDistinctName");
        List<String> sets = q.getResultList();
        return sets;
    }

    public List<NiseeColourComboSet> getComboSets() {
        Query q = em.createNamedQuery("NiseeColourComboSet.findAll");
        List<NiseeColourComboSet> sets = q.getResultList();
        return sets;
    }

    public String getComboset(String testname) {
        //Query q = em.createQuery(TYPE_ID_BY_NAME+testname);
        //System.out.println("15423");
        Query q = em.createNamedQuery("NiseeTestType.findByName");
        q.setParameter("name", testname);
        int id = ((NiseeTestType) q.getSingleResult()).getColourCombosetId();
        q = em.createNamedQuery("NiseeColourComboSet.findByColourCombosetId");
        q.setParameter("colourCombosetId", id);
        String name = (String) q.getSingleResult();
        return name;
    }

    public List<Color> getColourComboByID(int id) {
        Query q = em.createNamedQuery("NiseeColourCombo");
        NiseeColourCombo niseeColourCombo = em.find(NiseeColourCombo.class, id);
        List<Color> colors = new ArrayList<Color>();
        colors.add(NiseeColourToColor(niseeColourCombo.getNiseeColour1()));
        colors.add(NiseeColourToColor(niseeColourCombo.getNiseeColour()));
        colors.add(NiseeColourToColor(niseeColourCombo.getNiseeColour2()));
        return colors;
    }

    public List<NiseeColourComboSet> getComboset(int coloursetID) {
        Query q = em.createNamedQuery("NiseeColourComboSet.findByColourCombosetId");
        q.setParameter("colourCombosetId", Integer.valueOf(coloursetID));
        List<NiseeColourComboSet> sets = q.getResultList();
        return sets;
    }

    public String NiseeColourToHex(NiseeColour niseeColour) {
        Color color = new Color(niseeColour.getRed(), niseeColour.getGreen(), niseeColour.getBlue());
//        System.out.println(Integer.toHexString(color.getRGB() & 0x00ffffff));
        return "#" + Integer.toHexString(color.getRGB() & 0x00ffffff);
    }

    public Color NiseeColourToColor(NiseeColour niseeColour) {
        return new Color(niseeColour.getRed(), niseeColour.getGreen(), niseeColour.getBlue());
    }

    public NiseeColour HexToNiseeColour(String str) {
        NiseeColour niseeColour = new NiseeColour();
        System.out.println(str);
        Color color = Color.decode("0x" + str);
//        Color color = Color.decode("0x000000");
        niseeColour.setRed((short) color.getRed());
        niseeColour.setGreen((short) color.getGreen());
        niseeColour.setBlue((short) color.getBlue());
        return niseeColour;
    }

    public int addTestType(String name, int id) {
        NiseeTestType niseeTestType = new NiseeTestType();
        niseeTestType.setName(name);
        niseeTestType.setColourCombosetId(id);
        em.getTransaction().begin();
        em.persist(niseeTestType);
        em.getTransaction().commit();
        return niseeTestType.getTypeId();
    }

    public int addColourComboSet(String name) {

        //Create New NiseeColourComboSet
        NiseeColourComboSet niseeColourComboSet = new NiseeColourComboSet();
        niseeColourComboSet.setName(name);
        //ColourCombosetId using the defalut 0
        niseeColourComboSet.setColourCombosetId(0);

        //Set the Nisee Colour Combo
        Query q = em.createNamedQuery("NiseeColourCombo.findByColourComboId");
        q.setParameter("colourComboId", DEFAULTCOLOUR);
        NiseeColourCombo niseeColourCombo = (NiseeColourCombo) q.getSingleResult();
        niseeColourComboSet.setNiseeColourCombo(niseeColourCombo);

        em.getTransaction().begin();
        em.persist(niseeColourComboSet);
        em.getTransaction().commit();

        //Modify the ColourCombosetId with the ID
        int id = niseeColourComboSet.getId();
        niseeColourComboSet.setColourCombosetId(id);

        em.getTransaction().begin();
        em.persist(niseeColourComboSet);
        em.getTransaction().commit();

        return id;
    }

    public int addColourCombo(String fore1, String fore2, String back) {
        NiseeColourCombo niseeColourCombo = new NiseeColourCombo();

        em.getTransaction().begin();

        NiseeColour fore1NiseeColour = HexToNiseeColour(fore1);
        em.persist(fore1NiseeColour);
        niseeColourCombo.setNiseeColour1(fore1NiseeColour);

        NiseeColour fore2NiseeColour = HexToNiseeColour(fore2);
        em.persist(fore2NiseeColour);
        niseeColourCombo.setNiseeColour(fore2NiseeColour);

        NiseeColour backNiseeColour = HexToNiseeColour(back);
        em.persist(backNiseeColour);
        niseeColourCombo.setNiseeColour2(backNiseeColour);

        em.persist(niseeColourCombo);

        em.getTransaction().commit();
        return niseeColourCombo.getColourComboId();
    }

    public boolean deleteColourCombo(int id) {
        em.getTransaction().begin();
        NiseeColourCombo niseeColourCombo = em.find(NiseeColourCombo.class, id);
        if (niseeColourCombo != null) {
            NiseeColour fore1 = niseeColourCombo.getNiseeColour1();
            NiseeColour fore2 = niseeColourCombo.getNiseeColour();
            NiseeColour back = niseeColourCombo.getNiseeColour2();
            em.remove(niseeColourCombo);
            em.remove(fore1);
            em.remove(fore2);
            em.remove(back);
            em.getTransaction().commit();
        }
        return true;
    }

    public boolean deleteColourComboSet(int id) {
        em.getTransaction().begin();
        NiseeColourComboSet niseeColourComboSet = em.find(NiseeColourComboSet.class, id);
        if (niseeColourComboSet != null) {
            em.remove(niseeColourComboSet);
            em.getTransaction().commit();
        }
        return true;
    }

    public List<ColourCombo> getCombosNotInColourComboSetId(int id) {

        return getAllCombos();
    }

    public List<ColourCombo> getCombosByColourComboSetId(int id) {
        //Get NiseeColourCombo By ID
        Query q = em.createNamedQuery("NiseeColourComboSet.findByColourCombosetId");
        q.setParameter("colourCombosetId", id);
        List<NiseeColourComboSet> sets = q.getResultList();

        //Get NiseeColours of NiseeColourCombo
        Query qNiseeColour = em.createNamedQuery("NiseeColour.findByColourId");

        //Creat a list of ColourCombo to return
        List<ColourCombo> colourCombos = new ArrayList<ColourCombo>();

        for (NiseeColourComboSet niseeColourComboSet : sets) {
            NiseeColourCombo niseeColourCombo = niseeColourComboSet.getNiseeColourCombo();
            qNiseeColour.setParameter("colourId", niseeColourCombo.getNiseeColour1().getColourId());
            NiseeColour foreNiseeColour1 = (NiseeColour) qNiseeColour.getSingleResult();
            qNiseeColour.setParameter("colourId", niseeColourCombo.getNiseeColour().getColourId());
            NiseeColour foreNiseeColour2 = (NiseeColour) qNiseeColour.getSingleResult();
            qNiseeColour.setParameter("colourId", niseeColourCombo.getNiseeColour2().getColourId());
            NiseeColour backNiseeColour = (NiseeColour) qNiseeColour.getSingleResult();

//            System.out.println(niseeColourCombo.getName()+" "+colourCombo.getId());
            if (niseeColourCombo.getColourComboId() != DEFAULTCOLOUR) {
                colourCombos.add(new ColourCombo(
                        niseeColourCombo.getColourComboId(),
                        NiseeColourToHex(foreNiseeColour1),
                        NiseeColourToHex(foreNiseeColour2),
                        NiseeColourToHex(backNiseeColour),
                        niseeColourComboSet.getColourCombosetId(),
                        niseeColourComboSet.getId()));
            }
        }
        return colourCombos;
    }

    public List<ColourCombo> getColourComboByTestID(int testTypeID) {
        NiseeTestType niseeTestType = em.find(NiseeTestType.class, testTypeID);
        int colourCombosetId = niseeTestType.getColourCombosetId();
        return getCombosByColourComboSetId(colourCombosetId);
    }

    public boolean addColorComboToSet(int setID, List<Integer> ids) {
        em.getTransaction().begin();

        for (int i : ids) {
            NiseeColourComboSet niseeColourComboSet = new NiseeColourComboSet();
            niseeColourComboSet.setColourCombosetId(setID);
            NiseeColourCombo niseeColourCombo = new NiseeColourCombo(i);
            niseeColourComboSet.setNiseeColourCombo(niseeColourCombo);
            em.persist(niseeColourComboSet);
        }
        em.getTransaction().commit();
        return true;
    }

    public List<ColourCombo> getAllCombos() {
        //Get All NiseeColourCombo
        Query q = em.createNamedQuery("NiseeColourCombo.findAll");
        List<NiseeColourCombo> sets = q.getResultList();

        //Get NiseeColours of NiseeColoourCombo
        Query qNiseeColour = em.createNamedQuery("NiseeColour.findByColourId");

        //Creat a list of ColourCombo to return
        List<ColourCombo> colourCombos = new ArrayList<ColourCombo>();

        for (NiseeColourCombo niseeColourCombo : sets) {
            qNiseeColour.setParameter("colourId", niseeColourCombo.getNiseeColour1().getColourId());
            NiseeColour foreNiseeColour1 = (NiseeColour) qNiseeColour.getSingleResult();
            qNiseeColour.setParameter("colourId", niseeColourCombo.getNiseeColour().getColourId());
            NiseeColour foreNiseeColour2 = (NiseeColour) qNiseeColour.getSingleResult();
            qNiseeColour.setParameter("colourId", niseeColourCombo.getNiseeColour2().getColourId());
            NiseeColour backNiseeColour = (NiseeColour) qNiseeColour.getSingleResult();

//            System.out.println(niseeColourCombo.getName()+" "+colourCombo.getId());
            if (niseeColourCombo.getColourComboId() != DEFAULTCOLOUR) {
                colourCombos.add(new ColourCombo(niseeColourCombo.getColourComboId(),
                        NiseeColourToHex(foreNiseeColour1),
                        NiseeColourToHex(foreNiseeColour2),
                        NiseeColourToHex(backNiseeColour),
                        niseeColourCombo.getColourComboId()));
            }
        }
        return colourCombos;
    }

    /*public boolean createColourComboSet(NiseeColourCombo[] colourCombos){
    NiseeColourComboSet colourComboSet = new NiseeColourComboSet();
    for(NiseeColourCombo colourCombo: colourCombos)
    {
    colourComboSet.setNiseeColourCombo(colourCombo);
    }
    return false;
    }*/
    public EntityManager getEntityManager() {
        return em;
    }

    public NiseeUser refreshuser(NiseeUser tofresh) {
        em.getTransaction().begin();
        NiseeUser user = em.find(NiseeUser.class, tofresh.getUserUSERNAME());
        user =getUser(user.getUserUSERNAME());
        em.getTransaction().commit();
     
        return user;
    }

    public void refresh(Object torefresh) {
        em.refresh(torefresh);

    }

    public int storeImage(byte[] imagedata) {
        NiseeImage img = new NiseeImage();
        img.setImageIMAGEFILE(imagedata);
        em.getTransaction().begin();
        em.persist(img);
        em.getTransaction().commit();

        return img.getImageIMAGEID();
    }

    public int storeImage(byte[] imagedata, NiseeTestShape testShape) {
        NiseeImage img = new NiseeImage();
        img.setImageIMAGEFILE(imagedata);
        img.setImageIMAGETIMESTAMP(getDate());
        img.setNiseeTestShape(testShape);
        em.getTransaction().begin();
        em.persist(img);
        em.getTransaction().commit();
        return img.getImageIMAGEID();
    }

    public NiseeImage createNiseeImage(byte[] imagedata, int testShapeID) {
        NiseeImage img = new NiseeImage();
        img.setImageIMAGEFILE(imagedata);
        //img.setTestShapeID(testShapeID);
        em.getTransaction().begin();
        em.persist(img);
        em.getTransaction().commit();
        return img;
    }

 

    public void cleanGroup(int id) {
        em.getTransaction().begin();
        NiseeTestGroup delete = em.find(NiseeTestGroup.class, id);
        em.remove(delete);
        em.getTransaction().commit();
    }

    public NiseeTestGroup getGroup(int id) {
        Query q = null;
        q = em.createNamedQuery("NiseeTestGroup.findByTestGroupId");
        q.setParameter("testGroupId", id);
        NiseeTestGroup group = null;
        try {
            group = (NiseeTestGroup) q.getSingleResult();
        } catch (NoResultException e) {
            System.out.println(e);
            return null;
        }
        return group;

    }

    public String[] getAnswer(int image_id, String type) {
        String[] ans = {"No more use"};
        return ans;
    }

    public void cleanUnfinished(NiseeUser user) {
        System.out.println("Cleaning un saved ");
        for (NiseeTestGroup toclean : user.getNiseeTestGroupCollection()) {
            if (toclean.getTestDIAGNOSIS().equalsIgnoreCase("unsaved")) {
                em.getTransaction().begin();
                NiseeTestGroup clean = em.find(NiseeTestGroup.class, toclean.getTestGroupId());
                em.remove(clean);
                em.getTransaction().commit();
                em.clear();

            }

        }

    }

    public NiseeTestGroup quickStart(NiseeUser usr, int total,int typeid) {
        
        int maxGroup = maxGroup(usr) + 1;
        em.getTransaction().begin();
        NiseeTestGroup group = new NiseeTestGroup();
        System.out.println("Curr Date + " + getDate());

        group.setTestDATE(getDate());
        group.setTestDIAGNOSIS("unsaved");
        group.setNiseeUser(usr);
        group.setTestGROUP(maxGroup);
        em.persist(group);
        em.getTransaction().commit();
ArrayList<Integer> ids = new ArrayList<Integer>();
        System.out.println("Test type id" + typeid);
        NiseeTestType testtype = getTestByID(String.valueOf(typeid));
        for(NiseeTestShape shape :  testtype.getNiseeTestShapeCollection()){
            for(NiseeImage img : shape.getNiseeImageCollection()){
                ids.add(img.getImageIMAGEID());
                
            }
        }
     
        if (total > ids.size()) {
            total = ids.size();
        }
        Collections.shuffle(ids);
        ids.subList(0, total);
        List<Integer> idss = ids.subList(0, total);
        Collection<NiseeTestSingle> singles = group.getNiseeTestSingleCollection();
        NiseeTestSingle single;
        for (Integer s : idss) {
            single = new NiseeTestSingle(s.intValue(), group.getTestGroupId());
            singles.add(single);
        }
        em.getTransaction().begin();
        NiseeTestGroup newgroup = em.find(NiseeTestGroup.class, group.getTestGroupId());
        newgroup.setNiseeTestSingleCollection(singles);
        em.getTransaction().commit();
        return group;
    }

    public boolean checkPercSize(NiseeTestType test) {
        Iterator<NiseeTestShape> it = test.getNiseeTestShapeCollection().iterator();
        while (it.hasNext()) {
            if (it.next().getNiseePercentageSizeCollection().size() > 0) {
                return true;
            }
        }
        return false;
    }

    public boolean checkFormatGapSize(NiseeTestType test) {
        Iterator<NiseeTestShape> it = test.getNiseeTestShapeCollection().iterator();
        while (it.hasNext()) {
            if (it.next().getNiseeFormatGapsize() != null) {
                return true;
            }
        }
        return false;
    }

    public int getNiseeImageID(NiseeTestShape testShape, NiseeColourCombo colourCombo) {
        ImageGenerator generator = new ImageGenerator();
        short format = 0, gap = 0;
        ArrayList percentages = new ArrayList();
        ArrayList sizes = new ArrayList();
        ArrayList theFirstForeground = new ArrayList();
        ArrayList theSecondForeground = new ArrayList();
        Color foreground1Colour = null, foreground2Colour = null, backgroundColour = null;
        NiseeShape foregroundA = testShape.getNiseeShape1();
        NiseeShape foregroundB = testShape.getNiseeShape();
        NiseeFormatGapsize format_gap_parameters = testShape.getNiseeFormatGapsize();
        Collection<NiseePercentageSize> perc_size_parameters = testShape.getNiseePercentageSizeCollection();
        format = format_gap_parameters.getFormat();
        gap = format_gap_parameters.getGapsize();
        //get ArrayList percentages, sizes
        for (NiseePercentageSize i : perc_size_parameters) {
            percentages.add(i.getPercentages());
            sizes.add(i.getSize());
        }
        foreground1Colour = getColour(colourCombo.getNiseeColour1());
        foreground2Colour = getColour(colourCombo.getNiseeColour());
        backgroundColour = getColour(colourCombo.getNiseeColour2());
        //get theFirstForeground
        Collection<NiseeShapeCoor> shapes = foregroundA.getNiseeShapeCoorCollection();
        for (NiseeShapeCoor shape : shapes) {
            if (format == generator.CIRCLE) {
                niCircle myShape = new niCircle(shape.getCoorX(), shape.getCoorY(), shape.getScale());
                theFirstForeground.add(myShape);
            } else {
                niSquare myShape = new niSquare(shape.getCoorX(), shape.getCoorY(), shape.getScale());
                theFirstForeground.add(myShape);
            }
        }
        //get theSecondForeground
        Collection<NiseeShapeCoor> shapesB = foregroundB.getNiseeShapeCoorCollection();
        for (NiseeShapeCoor shape : shapesB) {
            if (format == generator.CIRCLE) {
                niCircle myShape = new niCircle(shape.getCoorX(), shape.getCoorY(), shape.getScale());
                theSecondForeground.add(myShape);
            } else {
                niSquare myShape = new niSquare(shape.getCoorX(), shape.getCoorY(), shape.getScale());
                theSecondForeground.add(myShape);
            }
        }
        System.out.println("9debug");
        /*System.err.println("foreground has: " + theFirstForeground.size() + " elements");
        System.err.println("foreground2 has: " + theSecondForeground.size() + " elements");
        System.err.println("percentages used: " + percentages.size());
        System.err.println("sizes used: " + sizes.size());
        System.err.println("format: " + format);
        System.err.println("gap: " + gap);
        System.err.println("fColour1: " + colourCombo.getNiseeColour1());
        System.err.println("fColour2: " + colourCombo.getNiseeColour());
        System.err.println("backClour: " + colourCombo.getNiseeColour2());*/

        BufferedImage buffer = generator.CreateImage(theFirstForeground, theSecondForeground, format, percentages, sizes, gap, foreground1Colour, foreground2Colour, backgroundColour);
        System.out.println("Image created");
        //write to bytes
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            if(buffer!=null)
            ImageIO.write(buffer, "jpg", baos);
        } catch (IOException e) {
        }
        byte[] imageBytes = baos.toByteArray();
        return storeImage(imageBytes, testShape);
    }

    public Color getColour(NiseeColour colour) {
        return new Color(colour.getRed(), colour.getGreen(), colour.getBlue());
    }

    public NiseeTestType getTestByName(String testName) {
        Query q = null;
        q = em.createNamedQuery("NiseeTestType.findByName");
        q.setParameter("name", testName);
        NiseeTestType test = null;
        try {
            test = (NiseeTestType) q.getSingleResult();
            if (test == null) {
                System.out.println("!!");
            }
        } catch (NoResultException e) {
            System.out.println(e);
            return null;
        }
        return test;
    }
    public NiseeTestType getTestByID(String id){
        Query q = null;
        q = em.createNamedQuery("NiseeTestType.findByTypeId");
        q.setParameter("typeId", Integer.valueOf(id));
        NiseeTestType test = null;
        try {
            test = (NiseeTestType) q.getSingleResult();
            if (test == null) {
                System.out.println("!!");
            }
        } catch (NoResultException e) {
            System.out.println(e);
            return null;
        }
        return test;

    }


    public NiseeTestGroup newTest(NiseeUser usr, String testType) {
        int maxGroup = maxGroup(usr) + 1;
        em.getTransaction().begin();
        NiseeTestGroup group = new NiseeTestGroup();
        System.out.println("Curr Date + " + getDate());
        Collection<NiseeTestSingle> singles = new ArrayList<NiseeTestSingle>();

        group.setTestDATE(getDate());
        group.setTestDIAGNOSIS("unsaved");
        group.setNiseeUser(usr);
        group.setTestGROUP(maxGroup);
        em.persist(group);
        em.getTransaction().commit();
        System.out.println("testtype +" +testType );
        NiseeTestType test = getTestByID(testType);

        //get images in test
        List<NiseeTestShape> imagesInTest = new ArrayList(test.getNiseeTestShapeCollection());
        List<NiseeColourComboSet> colourComboSet = getComboset(test.getColourCombosetId());

        Iterator<NiseeTestShape> imagesInTestIterator = imagesInTest.iterator();

        Collections.shuffle(imagesInTest);
        Collections.shuffle(colourComboSet);
        NiseeTestShape foreground = imagesInTestIterator.next();

        for (NiseeColourComboSet colourCombo : colourComboSet) {
            if (colourCombo.getNiseeColourCombo().getColourComboId() != DEFAULTCOLOUR) {
                System.out.println("2Curr Date + " + getDate());
                NiseeTestSingle single;
                int imageID = getNiseeImageID(foreground, colourCombo.getNiseeColourCombo());
                single = new NiseeTestSingle(imageID, group.getTestGroupId());
                singles.add(single);
                if (!imagesInTestIterator.hasNext()) {
                    imagesInTestIterator = imagesInTest.iterator();
                }
                foreground = imagesInTestIterator.next();
                //update progrees bar

                System.out.println("3Curr Date + " + getDate());
            }
        }
        em.getTransaction().begin();
        NiseeTestGroup newgroup = em.find(NiseeTestGroup.class, group.getTestGroupId());
        newgroup.setNiseeTestSingleCollection(singles);
        em.getTransaction().commit();
        return group;
    }

    public void saveProfile(NiseeUser user) {
        System.out.println("HERERERE!!!");
        em.getTransaction().begin();
        NiseeUser toupdate = em.find(NiseeUser.class, user.getUserUSERNAME());
        toupdate.setUserEMAIL(user.getUserEMAIL());
        toupdate.setUserFAMILYNAME(user.getUserFAMILYNAME());
        toupdate.setUserFIRSTNAME(user.getUserFIRSTNAME());
        toupdate.setUserGENDER(user.getUserGENDER());
//        toupdate.setUserDOB(java.sql.Date.valueOf(user.get));
        em.getTransaction().commit();

    }

    public void keepAnswer(HashMap<Integer, String> id_answer, int groupid) {
        NiseeTestGroup group = getGroup(groupid);
        boolean testpass = true;
        em.getTransaction().begin();
        for (NiseeTestSingle single : group.getNiseeTestSingleCollection()) {
            int image_id = single.getNiseeTestSinglePK().getImageIMAGEID();
            String answer = id_answer.get(image_id);
            System.out.println("Collection size " + group.getNiseeTestSingleCollection().size());
            System.out.println("persistance image_id:" + image_id + " answer:" + answer);
            NiseeImage single_img = getImage(image_id);
            System.out.println("Image id" + single_img.getImageIMAGEID());
            System.out.println("shape id " + single_img.getImageIMAGEID());
            System.out.println("Answers size " + single_img.getNiseeTestShape().getNiseeAnswerCollection().size());

//            System.out.println("TestTypeID" + single.getNiseeImage().getNiseeTestShape().getTestShapeId() + " Collection number" + single.getNiseeImage().getNiseeTestShape().getNiseeAnswerCollection().size());
            boolean singlepass = false;
            for (NiseeAnswer corrent_answer : single_img.getNiseeTestShape().getNiseeAnswerCollection()) {

                if (corrent_answer.getAnswer().equalsIgnoreCase(answer)) {

                    singlepass = true;
                }
            }
            if (!singlepass) {
                testpass = false;
            }
            single.setUserAnswer(answer);
            em.persist(single);
        }
        NiseeTestGroup toupdate = em.find(NiseeTestGroup.class, groupid);
        if (testpass) {
            toupdate.setTestDIAGNOSIS("PASS");
        } else {
            toupdate.setTestDIAGNOSIS("FAIL");
        }

        em.getTransaction().commit();

    }

    public void close() {
        em.close();
        emf.close();

    }

    public NiseeUser login(String username, String password) {
        if (username.isEmpty() || password.isEmpty()) {
            return null;
        }
        password = MD5toString(password);
        em.clear();
        em = getEntityManager();
        Query q = null;
        q = em.createNamedQuery("NiseeUser.findByUserPASSWORDandUSERNAME").setHint("toplink.refresh", "true");
        q.setParameter("userUSERNAME", username);
        q.setParameter("userPASSWORD", password);
//        q.setParameter("userPRIVILEGES", level);
//        System.out.println("username" +username + " passwd" + password );
        NiseeUser user = null;
        try {
            user = (NiseeUser) q.getSingleResult();
            em.refresh(user);
        } catch (NoResultException e) {

            return null;
        }
        return user;
    }

    public NiseeImage getImage(int id) {
        Query q = null;
        NiseeImage image;
        q = em.createNamedQuery("NiseeImage.findByImageIMAGEID");
        q.setParameter("imageIMAGEID", id);
        try {
            image = (NiseeImage) q.getSingleResult();
            System.out.println(image.getImageIMAGEID());

        } catch (NoResultException e) {
            return null;
        }
        return image;

    }

    public List getAdmins() {
        Query q = em.createNativeQuery("NiseeUser.findByUserPRIVILEGES");
        q.setParameter("userPRIVILEGES", 1);
        try {
            return q.getResultList();
        } catch (NoResultException e) {
            e.printStackTrace();
            return null;
        }
    }

    public int maxGroup(NiseeUser user) {
        int max = 0;
        for (NiseeTestGroup group : user.getNiseeTestGroupCollection()) {
            if (group.getTestGROUP() > max) {
                max = group.getTestGROUP();
            }
        }

        return max;
    }

    public Date getDate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd ");
        java.util.Date date = new java.util.Date();
        return date;


    }

    public List<NiseeUser> getUsers() {
        Query q = em.createNamedQuery("NiseeUser.findAll");
        List<NiseeUser> resultList = q.getResultList();
        return resultList;
    }

    public void addUser(NiseeUser user) {
        em.getTransaction().begin();
        em.persist(user);
        em.getTransaction().commit();
    }

    public NiseeUser getUser(String username) {
        em.clear();

        Query q = em.createNamedQuery("NiseeUser.findByUserUSERNAME");
        q.setParameter("userUSERNAME", username);
        NiseeUser user = null;
        try {
            user = (NiseeUser) q.getSingleResult();
            if (user != null) {
                em.refresh(user);
            }
        } catch (NoResultException e) {
            user = null;

        }
        return user;
    }

    public static String MD5toString(String input) {

        String res = "";
        try {
            MessageDigest algorithm = MessageDigest.getInstance("MD5");
            algorithm.reset();
            algorithm.update(input.getBytes());
            byte[] md5 = algorithm.digest();
            String tmp = "";
            for (int i = 0; i < md5.length; i++) {
                tmp = (Integer.toHexString(0xFF & md5[i]));
                if (tmp.length() == 1) {
                    res += "0" + tmp;
                } else {
                    res += tmp;
                }
            }
        } catch (NoSuchAlgorithmException ex) {
            System.out.println(ex);
        }
        return res;
    }
}
